<?php
/*
Plugin Name: 腾讯云存储
Plugin URI: https://www.beizigen.com/post/wordpress-tencent-cloud-object-storage-cos-plug-in-support-the-application-space-of-non-writable-data/
Description: 上传附件实时同步到腾讯COS，支持定时备份数据库。
Version: 1.1.4
Author: 背字根
Author URI: https://www.beizigen.com/
Text Domain: wp-cos
License: GPL v3 or later
License URI: http://www.gnu.org/licenses/gpl-3.0.txt
*/
require_once('includes/Mysqldump.php');
require_once('includes/class-cos.php');
require_once('includes/functions.php');
require_once('includes/dump.php');

//激活插件
register_activation_hook(__FILE__, function () {
	global $wp_rewrite;
	$wp_rewrite->flush_rules();
});

//停用插件
register_deactivation_hook(__FILE__, 'cos_delete_cron');

//卸载插件
register_uninstall_hook(__FILE__, 'cos_delete_cron');

function cos_control()
{
	$defaults = array(
		'appid' => '',
		'secret_id' => '',
		'secret_key' => '',
		'bucket_upload' => '',
		'bucket_backup' => '',
		'domain' => '',
		'cdn_target' => '',
		'local_attachment' => '',
		'gravatar' => '',
		'image_style' => '',
		'watermark' => '',
		'watermark_text' => '',
		'image_compress' => '',
	);
	$options = get_option('wp_cos');
	$options = unserialize($options);
	$options = wp_parse_args($options, $defaults);

	$error = new WP_Error;

	if (isset($_POST['action'])) {
		//API设置
		if (in_array($_POST['action'], ['api', 'plugin', 'image'])) {
			foreach ($options as $key => $val) {
				if (isset($_POST[$key])) {
					$options[$key] = sanitize_text_field($_POST[$key]);
					if ($key == 'domain') {
						$options[$key] = untrailingslashit($options[$key]);
					}
				}
			}

			update_option('wp_cos', serialize($options));
			$error->add('info', '设置保存成功！');

			if ('plugin' == $_POST['action']) {
				cos_delete_cron();
				if ($_POST['cycle'] != 'off') {
					wp_schedule_event(time(), $_POST['cycle'], 'wp_cos');
				}
			}

			if ('image' == $_POST['action'] && 'image' == $_POST['watermark']) {
				if ($_FILES['file']['error'] > 0) {
					if ($_FILES['file']['error'] != 4) {
						$error->add('error', '上传错误代码：' . $_FILES['file']['error']);
					}
				} else {
					if ('image/png' == $_FILES['file']['type']) {
						$WPCOS = new WPCOS('upload');
						$WPCOS->upload('watermark.png', $_FILES['file']['tmp_name'], [
							'x-cos-acl' => 'public-read',
						]);
					} else {
						$error->add('error', '图片格式错误');
					}
					unlink($_FILES['file']['tmp_name']);
				}
			}
		}
		//盲水印提取
		if ('watermark' == $_POST['action']) {
			if ($_FILES['file']['error'] > 0) {
				if ($_FILES['file']['error'] != 4) {
					$error->add('error', '上传错误代码：' . $_FILES['file']['error']);
				}
			} elseif (!in_array($_FILES['file']['type'], ['image/png', 'image/jpg', 'image/jpeg', 'image/gif', 'image/webp'])) {
				$error->add('error', '图片格式错误');
			} else {
				$WPCOS = new WPCOS('upload');
				$pathinfo = pathinfo($_FILES['file']['name']);
				$watermark_waiting = 'watermark_waiting';
				$watermark_waiting .= isset($pathinfo['extension']) ? '.' . $pathinfo['extension'] : '';

				$response = $WPCOS->get_watermark($watermark_waiting, $_FILES['file']['tmp_name']);
				if (is_array($response)) {
					$watermark_view = $WPCOS->get_object('watermark_view.png');
					if (isset($response['ProcessResults']['Object']['WatermarkStatus'])) {
						if ($response['ProcessResults']['Object']['WatermarkStatus'] > 60) {
							$error->add('info', '图片鉴权成功，该图片盲水印与预设置一致。');
						} else {
							$error->add('error', '图片鉴权失败，未提取到盲水印。');
						}
					} else {
						if ($watermark_view) {
							$error->add('info', '图片鉴权成功，该图片盲水印与预设置一致。');
							$WPCOS->delete('watermark_view.png');
							$watermark_view = 'data://image/png;base64,' . base64_encode($watermark_view);
						} else {
							$error->add('error', '图片鉴权失败，未提取到盲水印。');
						}
					}
					$WPCOS->delete($watermark_waiting);
				} elseif ($response) {
					$error->add('error', $response);
				}
			}
		}
		//备份数据库
		if ('backup' == $_POST['action']) {
			$backup = cos_backup_mysql();
			if ($backup->get_error_message('error')) {
				$error->add('error', $backup->get_error_message('error'));
			} else {
				$error->add('info', '备份数据库成功：' . $backup->get_error_message('info'));
			}
		}
		//初始同步
		if ('initialize' == $_POST['action']) {
			if (function_exists('set_time_limit')) {
				set_time_limit(0);
				if (function_exists('ignore_user_abort')) {
					ignore_user_abort(true);
				}
				$attachments = cos_get_attachment_ids();
				if ($attachments) {
					$msg = cos_initialize_sync($attachments);
					$error->add('info', $msg);
				} else {
					$error->add('error', '没有找到任何附件。');
				}
			} else {
				$error->add('error', '该功能需要set_time_limit函数支持，请联系主机服务商开启。');
			}
		}
	}

	$cycle = wp_get_schedule('wp_cos');
	$tab = isset($_GET['tab']) ? $_GET['tab'] : 'tools';
	$page = admin_url('admin.php?page=wp-cos');

?>
	<link rel="stylesheet" href="<?php echo plugin_dir_url(__FILE__); ?>css/wp-cos.css">
	<div class="mywrap wp-clearfix">
		<nav id="tabs">
			<ul>
				<li<?php echo 'tools' == $tab ? ' class="active"' : ''; ?>><a href="<?php echo $page; ?>&amp;tab=tools">实用工具</a></li>
					<li<?php echo 'api' == $tab ? ' class="active"' : ''; ?>><a href="<?php echo $page; ?>&amp;tab=api">API设置</a></li>
						<li<?php echo 'plugin' == $tab ? ' class="active"' : ''; ?>><a href="<?php echo $page; ?>&amp;tab=plugin">插件设置</a></li>
							<li<?php echo 'image' == $tab ? ' class="active"' : ''; ?>><a href="<?php echo $page; ?>&amp;tab=image">图像处理</a></li>
								<li<?php echo 'watermark' == $tab ? ' class="active"' : ''; ?>><a href="<?php echo $page; ?>&amp;tab=watermark">盲水印提取</a></li>
			</ul>
		</nav>

		<div id="content-box">
			<?php
			if ($error->has_errors()) {
				if ($error->get_error_message('error')) {
					echo '<div class="notice is-dismissible error">' . $error->get_error_message('error') . '</div>';
				} else {
					echo '<div class="notice is-dismissible success">' . $error->get_error_message('info') . '</div>';
				}
			}
			?>
			<?php if ('tools' == $tab) : ?>
				<form class="entry" method="post" action="<?php echo $page; ?>&amp;tab=tools">
					<h3>备份数据库</h3>
					<ul>
						<li>在插件设置中可以设置定时备份；</li>
						<li>更新文章后，可以使用本功能手动备份数据库到腾讯COS。</li>
					</ul>
					<p>
						<input class="button" type="submit" value="备份数据库" onclick="disabled=true; submit();">&nbsp;&nbsp;
						<button class="button" id="backup" onclick="disabled=true;">下载数据库</button>
						<input type="hidden" name="action" value="backup">
					</p>
				</form>
				<hr>
				<form class="entry" method="post" action="<?php echo $page; ?>&amp;tab=tools">
					<h3>初始同步</h3>
					<ul>
						<li>初始同步用于初次安装插件时，将以往上传的附件同步到腾讯COS；</li>
						<li>安装插件之后上传的附件会实时同步到腾讯COS；</li>
						<li>初始同步支持盲水印添加，但不支持其他图像处理；</li>
						<li>
							<?php
							if (function_exists('ignore_user_abort')) {
								echo '开始执行任务后，关闭网页也不影响任务执行；';
							} else {
								echo '联系服务器商开启ignore_user_abort函数，关闭网页也不影响任务执行；';
							}
							?>
						</li>
						<li>任务执行完毕会发送邮件到<?php echo get_bloginfo('admin_email'); ?>。</li>
					</ul>
					<p>
						<input class="button" type="submit" value="开始同步" onclick="disabled=true; submit();">
						<input type="hidden" name="action" value="initialize">
					</p>
				</form>
			<?php endif; ?>

			<?php if ('api' == $tab) : ?>
				<form method="post" action="<?php echo $page; ?>&amp;tab=api">
					<table class="form-table">
						<tbody>
							<tr>
								<th scope="row">
									<label for="appid">APPID</label>
								</th>
								<td>
									<input id="appid" name="appid" class="regular-text code" type="text" value="<?php echo $options['appid']; ?>" required>
									<p class="description">登录<a href="https://console.cloud.tencent.com/cam/capi" target="_blank" rel="nofollow">API 密钥管理 </a>创建。</p>
								</td>
							</tr>
							<tr>
								<th scope="row">
									<label for="secret-id">Secret ID</label>
								</th>
								<td>
									<input id="secret-id" name="secret_id" class="regular-text code" type="text" value="<?php echo $options['secret_id']; ?>" required>
									<p class="description">登录<a href="https://console.cloud.tencent.com/cam/capi" target="_blank" rel="nofollow">API 密钥管理 </a>创建。</p>
								</td>
							</tr>
							<tr>
								<th scope="row">
									<label for="secret-key">Secret Key</label>
								</th>
								<td>
									<input id="secret-key" name="secret_key" class="regular-text code" type="text" value="<?php echo $options['secret_key']; ?>" required>
									<p class="description">登录<a href="https://console.cloud.tencent.com/cam/capi" target="_blank" rel="nofollow">API 密钥管理</a>创建。</p>
								</td>
							</tr>
							<tr>
								<th scope="row">
									<label for="bucket-upload">附件Bucket</label>
								</th>
								<td>
									<input id="bucket-upload" name="bucket_upload" class="regular-text code" type="text" value="<?php echo $options['bucket_upload']; ?>">
									<p class="description">存放附件的Bucket名称，<a href="https://curl.qcloud.com/USVjrwwc" target="_blank" rel="nofollow">开通COS</a>，然后<a href="https://console.cloud.tencent.com/cos" target="_blank" rel="nofollow">创建存储桶</a>。</p>
								</td>
							</tr>
							<tr>
								<th scope="row">
									<label for="bucket-backup">备份Bucket</label>
								</th>
								<td>
									<input id="bucket-backup" name="bucket_backup" class="regular-text code" type="text" value="<?php echo $options['bucket_backup']; ?>">
									<p class="description">存放数据库备份的Bucket名称，<a href="https://curl.qcloud.com/USVjrwwc" target="_blank" rel="nofollow">开通COS</a>，然后<a href="https://console.cloud.tencent.com/cos" target="_blank" rel="nofollow">创建存储桶</a>。</p>
								</td>
							</tr>
							<tr>
								<th scope="row">
									<label for="domain">CDN域名</label>
								</th>
								<td>
									<input id="domaind" name="domain" class="regular-text code" type="url" value="<?php echo $options['domain']; ?>">
									<p class="description">填写<a href="https://curl.qcloud.com/hxcXtyRX" target="_blank" rel="nofollow">CDN</a>域名启用网站静态资源CDN加速，包括http(s)://。</p>
								</td>
							</tr>
						</tbody>
					</table>
					<p>
						<input class="button-primary" type="submit" value="保存设置">
						<input type="hidden" name="action" value="api">
					</p>
				</form>
			<?php endif; ?>

			<?php if ('plugin' == $tab) : ?>
				<form method="post" action="<?php echo $page; ?>&amp;tab=plugin">
					<table class="form-table">
						<tbody>
							<tr>
								<th scope="row"><label for="cycle">定时备份</label></th>
								<td>
									<select name="cycle" id="cycle">
										<option value="daily" <?php if ('daily' == $cycle) echo ' selected'; ?>>每天</option>
										<option value="weekly" <?php if ('weekly' == $cycle) echo ' selected'; ?>>每周</option>
										<option value="monthly" <?php if ('monthly' == $cycle) echo ' selected'; ?>>每月</option>
										<option value="off" <?php if (!$cycle) echo ' selected'; ?>>关闭定时</option>
									</select>
									<p class="description">定时备份仅针对数据库，附件是实时同步到云存储的。</p>
								</td>
							</tr>
							<tr>
								<th scope="row"><label for="cdn-target">加速范围</label></th>
								<td>
									<select name="cdn_target" id="cdn-target">
										<option value="content" <?php if ('content' == $options['cdn_target']) echo ' selected'; ?>>内容</option>
										<option value="site" <?php if ('site' == $options['cdn_target']) echo ' selected'; ?>>全站</option>
									</select>
									<p class="description">加速文章内容中的图片，或全站静态资源。</p>
								</td>
							</tr>
							<tr>
								<th scope="row"><label for="local-attachment">本地附件</label></th>
								<td>
									<select name="local_attachment" id="local-attachment">
										<option value="yes" <?php if ('yes' == $options['local_attachment']) echo ' selected'; ?>>保留</option>
										<option value="no" <?php if ('no' == $options['local_attachment']) echo ' selected'; ?>>删除</option>
									</select>
									<p class="description">是否保留本地附件，应用空间不支持写入时，例如<a href="https://curl.qcloud.com/BZjYbBSX" target="_blank" rel="nofollow">云函数</a>等产品，请选择删除。</p>
								</td>
							</tr>
							<tr>
								<th scope="row"><label for="gravatar">Gravatar头像加速</label></th>
								<td>
									<select name="gravatar" id="gravatar">
										<option value="off" <?php if ('off' == $options['gravatar']) echo ' selected'; ?>>关闭</option>
										<option value="on" <?php if ('on' == $options['gravatar']) echo ' selected'; ?>>开启</option>
									</select>
								</td>
							</tr>
						</tbody>
					</table>
					<p>
						<input class="button-primary" type="submit" value="保存设置">
						<input type="hidden" name="action" value="plugin">
					</p>
				</form>
			<?php endif; ?>

			<?php if ('image' == $tab) : ?>
				<form method="post" action="<?php echo $page; ?>&amp;tab=image" enctype="multipart/form-data">
					<table class="form-table">
						<tbody>
							<tr>
								<th scope="row"><label for="image-style">样式名称</label></th>
								<td>
									<input id="image-style" name="image_style" class="regular-text code" type="text" value="<?php echo $options['image_style']; ?>">
									<p class="description">使用<a href="https://console.cloud.tencent.com/cos5/bucket" target="_blank" rel="nofollow">COS样式处理规则</a>对上传的图片进行缩放、裁剪、格式转换等处理。</p>
								</td>
							</tr>
							<tr>
								<th scope="row"><label for="compress">高级压缩</label></th>
								<td>
									<select name="image_compress" id="image-compress">
										<option value="off" <?php if ('off' == $options['image_compress']) echo ' selected'; ?>>关闭</option>
										<option value="on" <?php if ('on' == $options['image_compress']) echo ' selected'; ?>>开启</option>
									</select>
									<p class="description">开启高级压缩后图片将转换为webp格式</p>
								</td>
							</tr>
							<tr>
								<th scope="row"><label for="watermark">盲水印</label></th>
								<td>
									<select name="watermark" id="watermark-type">
										<option value="off" <?php if ('off' == $options['watermark']) echo ' selected'; ?>>关闭</option>
										<option value="image" <?php if ('image' == $options['watermark']) echo ' selected'; ?>>图片</option>
										<option value="text" <?php if ('text' == $options['watermark']) echo ' selected'; ?>>文字</option>
									</select>


									<div id="watermark-text" <?php echo 'text' == $options['watermark'] ? ' class="show"' : '' ?>>
										<input type="text" name="watermark_text" class="regular-text code" value="<?php echo $options['watermark_text']; ?>">
										<p class="description">目前仅支持字母与数字</p>
									</div>

									<div id="watermark-image" <?php echo 'image' == $options['watermark'] ? ' class="show"' : '' ?>>
										<?php
										$watermark_img = '';
										if ('image' == $options['watermark']) {
											$WPCOS = new WPCOS('upload');
											$watermark_img = $WPCOS->get_object('watermark.png');

											if ($watermark_img) {
												$watermark_img = 'data://image/png;base64,' . base64_encode($watermark_img);
											}
										}
										if (!$watermark_img) {
											$watermark_img = plugin_dir_url(__FILE__) . '/images/none.png';
										}
										?>
										<img src="<?php echo $watermark_img; ?>" width="90">
										<input type="file" name="file" accept="image/png">
										<p class="description">必须为png格式</p>
									</div>
								</td>
							</tr>
						</tbody>
					</table>
					<p>
						<input class="button-primary" type="submit" value="保存设置">
						<input type="hidden" name="action" value="image">
					</p>
				</form>
			<?php endif; ?>

			<?php if ('watermark' == $tab) :
				if (empty($watermark_view)) {
					$watermark_view = plugin_dir_url(__FILE__) . '/images/none.png';
				}
			?>
				<div id="watermark" class="wp-clearfix">
					<div id="watermark-view">
						<img src="<?php echo $watermark_view; ?>" width="350">
					</div>
					<div id="up-watermark">
						<p>上传带有盲水印的图片，提取图片中隐藏的水印以鉴权。</p>
						<p>目标图片添加盲水印的方式需要与图像处理设置中的盲水印设置保持一致。</p>
						<form method="post" action="<?php echo $page; ?>&tab=watermark" enctype="multipart/form-data">
							<input type="file" name="file" accept="image/png|image/jpg|image/jpeg|image/gif|image/webp">
							<input type="hidden" name="action" value="watermark">
						</form>
					</div>
				</div>
			<?php endif; ?>
		</div>
	</div>

	<script type="text/javascript">
		jQuery(document).ready(function() {
			jQuery("#watermark-type").change(function() {
				var watermark_text = jQuery("#watermark-text");
				var watermark_image = jQuery("#watermark-image");
				if (jQuery(this).val() == "text") {
					watermark_image.removeClass("show");
					watermark_text.addClass("show");
				}
				if (jQuery(this).val() == "image") {
					watermark_text.removeClass("show");
					watermark_image.addClass("show");
				}
				if (jQuery(this).val() == "off") {
					watermark_text.removeClass("show");
					watermark_image.removeClass("show");
				}
			});

			jQuery("#watermark").change(function() {
				jQuery(this).find("form").submit();
			});

			jQuery("#backup").click(function() {
				jQuery.ajax({
					cache: false,
					type: "POST",
					url: ajaxurl,
					data: {
						"action": "dump"
					},
					dataType: "text",
					async: true,
					success: function(data) {
						data = atob(data);
						let arr = new Uint8Array(data.length);
						for (let i = 0; i < data.length; i++) {
							arr[i] = data.charCodeAt(i);
						}
						let blob = new Blob([arr], {
							type: "application/zip"
						});

						let elink = document.createElement("a");
						elink.download = "<?php echo DB_NAME; ?>.zip";
						elink.style.display = "none";
						elink.href = window.URL.createObjectURL(blob);
						document.body.appendChild(elink);
						elink.click();
						window.URL.revokeObjectURL(elink.href);
						document.body.removeChild(elink);
					},
					error: function(xhr, thrownError) {
						alert("Status：" + xhr.status + "\nState：" + xhr.readyState + "\nThrew：" + thrownError);
					}
				});

			});
		});
	</script>

<?php
}

//添加菜单
function cos_menu()
{
	add_menu_page('腾讯云存储', '腾讯云存储', 'administrator', 'wp-cos', 'cos_control', 'dashicons-cloud', 999);
}
add_action('admin_menu', 'cos_menu');
//插件页面设置链接
add_filter('plugin_action_links', function ($links, $file) {
	if ($file == plugin_basename(__FILE__)) {
		array_unshift($links, '<a href="admin.php?page=wp-cos">设置</a>');
	}
	return $links;
}, 10, 2);
?>